package routes

import (
	"bytes"
	"encoding/json"
	"mumu_stock_trad/reporter"
	"net/http"
	"strconv"
	"sync"
	"time"

	"github.com/gin-gonic/gin"
	log "github.com/sirupsen/logrus"
)

type bodyLogWriter struct {
	gin.ResponseWriter
	body *bytes.Buffer
}

func (w bodyLogWriter) Write(b []byte) (int, error) {
	w.body.Write(b)
	return w.ResponseWriter.Write(b)
}

// Metric metric middleware
func metric() gin.HandlerFunc {
	return func(c *gin.Context) {
		tBegin := time.Now()

		blw := &bodyLogWriter{body: bytes.NewBufferString(""), ResponseWriter: c.Writer}
		c.Writer = blw
		c.Next()

		duration := time.Since(tBegin)

		go func(method string, path string, status int, body string, duration time.Duration) {
			defer func() {
				if err := recover(); err != nil {
					log.Error("recover")
				}
			}()

			res := struct {
				ErrorCode    int    `json:"errorCode"`
				ErrorMessage string `json:"errorMessage"`
			}{}

			json.Unmarshal([]byte(body), &res)

			if status == http.StatusOK {
				reporter.MonitorHttpRequest(path, strconv.Itoa(res.ErrorCode), duration)
			} else {
				reporter.MonitorHttpRequest(path, strconv.Itoa(2324), duration)
			}

		}(c.Request.Method, c.Request.URL.Path, c.Writer.Status(), blw.body.String(), duration)
	}
}

func loadMisc(sr *gin.RouterGroup) {
	sr.Use(metric())

	/*  loadBalance 调用 */
	hc := sr.Group("/hc")
	{
		hc.GET("/healthcheck", HealthCheck)
		hc.GET("/set-status-unhealthy", SetStatusUnhealthy)
	}
	/*  loadBalance 调用 */
}

type healthy struct {
	status bool
	mutex  sync.RWMutex
}

var sys_healthy = healthy{
	status: true,
}

func (h *healthy) getStatus() bool {
	h.mutex.RLock()
	defer h.mutex.RUnlock()
	return h.status
}

func (h *healthy) setStatus(status bool) bool {
	h.mutex.Lock()
	defer h.mutex.Unlock()
	h.status = status
	return true
}

// 健康检查
func HealthCheck(c *gin.Context) {
	ret := "healthy"
	status := sys_healthy.getStatus()
	if !status {
		ret = "unhealthy"
		c.String(503, ret)
	} else {
		c.String(200, ret)
	}
}

// 健康状态设置
func SetStatusUnhealthy(c *gin.Context) {
	sys_healthy.setStatus(false)
	c.String(200, "success")
}
